package chapt03.stencil;
// Stencil.java
// OpenGL SuperBible, 3rd Edition
// Richard S. Wright Jr.
// rwright@starstonesoftware.com

import javax.media.opengl.GL2;

public class Stencil
{
	// Initial square position and size
	static float x = 0.0f;
	static float y = 0.0f;
	static float rsize = 25;
	
	// Step size in x and y directions
	// (number of pixels to move each time)
	static float xstep = 1.0f;
	static float ystep = 1.0f;
	
	// Keep track of windows changing width and height
	static float windowWidth;
	static float windowHeight;
	
	// Setup the rendering state
	// Called by GLUT library when the window has changed size
	protected static void setup(GL2 gl2, int w, int h)
	{	
		float aspectRatio;
		
		// Prevent a divide by zero
		if(h == 0)
			h = 1;
		
		// Set Viewport to window dimensions
		gl2.glViewport(0, 0, w, h);
		
		// Reset coordinate system
		gl2.glMatrixMode(GL2.GL_PROJECTION);
		gl2.glLoadIdentity();
		
		// Establish clipping volume (left, right, bottom, top, near, far)
		aspectRatio = (float)w / (float)h;
		if(w <= h)
		{
			windowWidth = 100;
			windowHeight = 100 / aspectRatio;
			gl2.glOrtho(-100.0, 100.0, -windowHeight, windowHeight, 1.0, -1.0);
		}
		else
		{
			windowWidth = 100 * aspectRatio;
			windowHeight = 100;
			gl2.glOrtho(-windowWidth, windowWidth, -100.0, 100.0, 1.0, -1.0);
		}
		
		gl2.glMatrixMode(GL2.GL_MODELVIEW);
		gl2.glLoadIdentity();
	}
	
	// Called to draw scene
	protected static void render(GL2 gl2, int w, int h)
	{
		// Reverse direction when you reach left or right edge
		if(x > windowWidth - rsize || x < -windowWidth)
			xstep = -xstep;
  	  
		// Reverse direction when you reach top or bottom edge
		if(y > windowHeight || y < -windowHeight + rsize)
			ystep = -ystep;
  	  
		// Check bounds.  This is in case the window is made
		// smaller while the rectangle is bouncing and the
		// rectangle suddenly finds itself outside the new
		// clipping volume.
		if(x > (windowWidth - rsize + xstep))
			x = windowWidth - rsize - 1;
  	  
		if(y > (windowHeight + ystep))
			y = windowHeight - 1;

		// Actually move the square
		x += xstep;
		y += ystep;
		
		double dRadius = 0.1; // Initial radius of spiral
		double dAngle;        // Looping variable
		
		// Clear blue window
		gl2.glClearColor(0.0f, 0.0f, 1.0f, 0.0f);
		
		// Use 0 for clear stencil, enable stencil test
		gl2.glClearStencil(0);
		gl2.glEnable(GL2.GL_STENCIL_TEST);
		
		// Clear color and stencil buffer
		gl2.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_STENCIL_BUFFER_BIT);
		
		// All drawing commands fail the stencil test, and are not
		// drawn, but increment the value in the stencil buffer.
		gl2.glStencilFunc(GL2.GL_NEVER, 0x0, 0x0);
		gl2.glStencilOp(GL2.GL_INCR, GL2.GL_INCR, GL2.GL_INCR);
		
		// Spiral pattern will create stencil pattern
		// Draw the spiral pattern with white lines.  We
		// make the lines white to demonstrate that the
		// stencil function prevents them from being drawn
		gl2.glColor3f(1.0f, 1.0f, 1.0f);
		gl2.glBegin(GL2.GL_LINE_STRIP);
			for(dAngle = 0; dAngle < 400.0; dAngle += 0.1)
			{
				gl2.glVertex2d(dRadius * Math.cos(dAngle), dRadius * Math.sin(dAngle));
				dRadius *= 1.002;
			}
		gl2.glEnd();
		
		// Now, allow drawing, except where the stencil pattern is 0x1
		// and do not make any further changes to the stencil buffer
		gl2.glStencilFunc(GL2.GL_NOTEQUAL, 0x1, 0x1);
		gl2.glStencilOp(GL2.GL_KEEP, GL2.GL_KEEP, GL2.GL_KEEP);
		
		// Now draw red bouncing square
		// (x and y) are modified by a timer function
		gl2.glColor3f(1.0f, 0.0f, 0.0f);
		gl2.glRectf(x, y, x + rsize, y - rsize);
		
		// All done, do the buffer swap
		gl2.glFlush();
		
	}
}